package org.emergent.lucidity.test;

import java.util.Properties;
import java.util.Enumeration;
import java.security.GeneralSecurityException;

public class PropertyExpander
{
    public static final String START_TOKEN = "${";
    public static final char END_TOKEN = '}';

    PropertyExpander()
    {
    }

    public static Properties expand( Properties props )
        throws GeneralSecurityException
    {
        return expand( props, System.getProperties() );
    }

    public static Properties expand( Properties props, Properties values )
        throws GeneralSecurityException
    {
        Properties newProps = new Properties();
        Enumeration propNamesEnum = props.propertyNames();
        while (propNamesEnum.hasMoreElements())
        {
            String propName = (String)propNamesEnum.nextElement();
            String value =
                expandUsingProperties( props.getProperty( propName ), values );
            newProps.setProperty( propName, value );
        }
        return newProps;
    }

    public static String expandSystemProperty( final String propname, final String defval )
    {
        return expandString( System.getProperty( propname, defval ) );
    }

    public static String expandSystemProperty( final String propname )
    {
        final String sysprop = System.getProperty( propname );
        if ( sysprop == null )
            return null;
        return expandString( sysprop );
    }

    public static String expandString(String s)
    {
        try
        {
            return expand( s );
        }
        catch (GeneralSecurityException ex)
        {
            return s; // not expanded
        }
    }

    public static String expand(String s)
        throws GeneralSecurityException
    {
        return expandUsingProperties( s, System.getProperties() );
    }


    public static String expandUsingProperties(String s, Properties props)
        throws GeneralSecurityException
    {
        /**
         * We are done if null.
         */
        if(s == null)
            return null;

        /**
         * Does the property have anything to expand?
         */
        int cur = s.indexOf(START_TOKEN, 0);
        if(cur == -1)
            return s;

        /**
         * Lets get to work...
         */
        StringBuffer stringbuffer = new StringBuffer(s.length());
        int end = s.length();
        int beg = 0;
        while(cur < end)
        {
            if(cur > beg)
            {
                stringbuffer.append(s.substring(beg, cur));
                beg = cur;
            }

            /**
             * Determine name to expand
             */
            int i;
            for(i = cur + START_TOKEN.length()
                ; i < end && s.charAt(i) != END_TOKEN
                ; i++
                );

            /**
             * Garbage or intent? If we are at the end, return the rest of
             * the string as is.
             */
            if(i == end)
            {
                //
                stringbuffer.append(s.substring(cur, i));
                break;
            }

            /**
             * Extract name
             */
            String propToExpand = s.substring(cur + 2, i);

            /**
             * Lookup name
             */
            if(propToExpand.equals("/"))
            {
                /**
                 * Special case for path separator.
                 */
                stringbuffer.append(java.io.File.separatorChar);
            }
            else
            {
                /**
                 * Find property in System env.
                 */
                String expandValue = props.getProperty(propToExpand);
                if(expandValue == null)
                    throw new GeneralSecurityException(
                        "unable to expand property " + propToExpand
                    );
                stringbuffer.append(expandValue);
            }

            /**
             * Anything else to expand?
             */
            beg = i + 1;
            cur = s.indexOf("${", beg);
            if(cur == -1)
            {
                if(beg < end)
                    stringbuffer.append(s.substring(beg, end));
                // DONE!!
                break;
            }
        }

        /**
         * Return expanded property
         */
        return stringbuffer.toString();
    }

}
